﻿namespace ChoBulkFileProcessor
{
    #region NameSpaces

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Threading;
    using Cinchoo.Core;
    using Cinchoo.Core.Configuration;
    using Cinchoo.Core.Win32.Dialogs;
    using System.Diagnostics;
    using Microsoft.Win32;
    using Cinchoo.Core.Diagnostics;
    using System.Reflection;
    using System.Xml.Linq;
    using Cinchoo.Core.IO;
    using Cinchoo.Core.Reflection;
    using Cinchoo.Core.WPF;
    using System.Collections.Specialized;
    using MahApps.Metro.Controls;

    #endregion NameSpaces

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : MetroWindow
    {
        #region Instance Members (Private)

        private readonly string Caption;
        private string _undoFilePath = null;
        private DispatcherTimer _dispatcherTimer;
        private Thread _mainUIThread;
        private Thread _fileNameProcessThread;
        private Thread _undoProcessThread;
        private ChoAppSettings _appSettings;
        private bool _isRunning = false;
        private bool _isUndoRunning = false;
        private bool _isDirty = false;
        private bool IsDirty
        {
            get { return _isDirty; }
            set { _isDirty = value; }
        }
        private string _settingsFilePath = null;
        public string SettingsFilePath
        {
            get { return _settingsFilePath; }
            private set
            {
                _settingsFilePath = value;
                IsDirty = false;
            }
        }
        ChoFileFolderProcessor _undoFileProcessor = null;
        ChoFileFolderProcessor _fileProcessor = null;
        private bool _wndLoaded = false;
        private string _plugInsFolder = null;
        private bool _cancelOps = false;
        ChoWPFBindableConfigObject<ChoAppSettings> _bindObj;

        #endregion Instance Members (Private)

        public MainWindow(string settingsFilePath = null)
        {
            SettingsFilePath = settingsFilePath;
            InitializeComponent();

            Caption = Title;
            Title = "{0} (v{1})".FormatString(Title, Assembly.GetEntryAssembly().GetName().Version);
        }

        private void MyWindow_Loaded(object sender1, RoutedEventArgs e1)
        {
            _bindObj = new ChoWPFBindableConfigObject<ChoAppSettings>();
            _appSettings = _bindObj.UnderlyingSource;
            if (!SettingsFilePath.IsNullOrWhiteSpace() && File.Exists(SettingsFilePath))
                _appSettings.LoadXml(File.ReadAllText(SettingsFilePath));
            else
                _appSettings.Reset();

            this.DataContext = _bindObj;
            _appSettings.BeforeConfigurationObjectLoaded += ((o, e) =>
                {
                    e.Cancel = (bool)this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                         new Func<bool>(() =>
                         {
                             if (IsDirty)
                             {
                                 if (MessageBox.Show("Configuration settings has been modified outside of the tool. {0}Do you want to reload it and lose the changes made in the tool?".FormatString(Environment.NewLine),
                                     Title, MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
                                     return false;
                                 else
                                     return true;
                             }

                             return false;
                         }));
                });

            _appSettings.AfterConfigurationObjectMemberSet += (o, e) => IsDirty = true;
            _appSettings.ConfigurationObjectMemberLoadError += _appSettings_ConfigurationObjectMemberLoadError;
            _appSettings.AfterConfigurationObjectPersisted += _appSettings_AfterConfigurationObjectPersisted;
            _appSettings.AfterConfigurationObjectLoaded += ((o, e) =>
                {
                    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                         new Action(() =>
                         {
                             IsDirty = false;
                         }));
                });

            _mainUIThread = Thread.CurrentThread;

            _dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
            _dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
            _dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000);
            _dispatcherTimer.Start();

            _plugInsFolder = _appSettings.PlugInsFolders;
            //Load plug-ins
            if (!_appSettings.PlugInsFolders.IsNullOrWhiteSpace())
            {
                foreach (string plugInFolder in _appSettings.PlugInsFolders.SplitNTrim())
                {
                    if (plugInFolder.IsNullOrWhiteSpace() || !Directory.Exists(plugInFolder)) continue;
                    ChoGlobalAssemblyFactory.Me.LoadAssemblies(plugInFolder);
                }
            }
            //((INotifyCollectionChanged)lstFolders.Items).CollectionChanged += FoldersCollectionChanged;
            ChoShellExtCmdLineArgs cmdLineArgs = new ChoShellExtCmdLineArgs();
            if (!cmdLineArgs.Directory.IsNullOrWhiteSpace())
                AddToFilesListBox(cmdLineArgs.Directory);
            else if (!_appSettings.Directories.IsNullOrWhiteSpace())
                AddToFilesListBox(_appSettings.Directories);
            IsDirty = false;
        }

        private void SaveDirectories()
        {
            StringBuilder msg = new StringBuilder();
            foreach (string folder in lstFolders.Items)
            {
                if (msg.Length == 0)
                    msg.Append(folder);
                else
                    msg.AppendFormat(";{0}", folder);
            }

            _appSettings.Directories = msg.ToString();
        }

        private void _appSettings_AfterConfigurationObjectPersisted(object sender, ChoConfigurationObjectEventArgs e)
        {
            //SaveSettings();
        }

        private void _appSettings_ConfigurationObjectMemberLoadError(object sender, Cinchoo.Core.Configuration.ChoConfigurationObjectMemberErrorEventArgs e)
        {
            MessageBox.Show(e.Exception.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Warning);
            e.Handled = true;
        }

        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            lstFolders.IsEnabled = !_isRunning;
            grpMove.IsEnabled = !_isRunning;
            grpFolders.IsEnabled = !_isRunning;
            btnRun.IsEnabled = !_isRunning;
            btnStop.IsEnabled = _isRunning;
            btnAddFolder.IsEnabled =  !_isRunning && !txtFolder.Text.IsNullOrWhiteSpace();
            btnDeleteFolder.IsEnabled = lstFolders.IsKeyboardFocusWithin && !_isRunning && lstFolders.SelectedItems.Count > 0;
            btnNewFile.IsEnabled = !_isRunning;
            btnOpenFile.IsEnabled = !_isRunning;
            btnSaveFile.IsEnabled = !_isRunning && IsDirty;
            btnSaveAsFile.IsEnabled = !_isRunning;
            if (SettingsFilePath.IsNullOrWhiteSpace())
            {
                this.ToolTip = null;
                tbSettingsName.Text = null;
            }
            else
            {
                this.ToolTip = SettingsFilePath;
                tbSettingsName.Text = Path.GetFileNameWithoutExtension(SettingsFilePath);
            }
            btnClear.IsEnabled = !_isRunning && txtStatus.Text.Length > 0;
            btnMoveCopyBrowse.IsEnabled = !_isRunning;
            txtCopyMoveToFolder.IsEnabled = !_isRunning;

            if (_isRunning)
                btnUndo.IsEnabled = false;
            else
                btnUndo.IsEnabled = !_undoFilePath.IsNullOrWhiteSpace() && File.Exists(_undoFilePath);

            if (_fileNameProcessThread != null && _fileNameProcessThread.IsAlive)
            {
                grpValidFileExts.IsEnabled = false;
                grpOptions.IsEnabled = false;
                grpMatch.IsEnabled = false;
            }
            else
            {
                grpValidFileExts.IsEnabled = true;
                grpOptions.IsEnabled = true;
                grpMatch.IsEnabled = true;
            }
            // Forcing the CommandManager to raise the RequerySuggested event
            CommandManager.InvalidateRequerySuggested();
        }

        private void btnBrowse_Click(object sender, RoutedEventArgs e)
        {
            ChoFolderBrowserDialog dlg1 = new ChoFolderBrowserDialog
            {
                Description = "Choose folder(s) to process...",
                ShowNewFolderButton = true,
                ShowEditBox = true,
                ShowBothFilesAndFolders = false,
                NewStyle = true,
                SelectedPath = (System.IO.Directory.Exists(txtFolder.Text)) ? txtFolder.Text : "",
                ShowFullPathInEditBox = false,
            };
            dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer;

            var result = dlg1.ShowDialog();

            if (result == System.Windows.Forms.DialogResult.OK)
            {
                if (Directory.Exists(dlg1.SelectedPath))
                    txtFolder.Text = dlg1.SelectedPath;
                else
                    txtFolder.Text = System.IO.Path.GetDirectoryName(dlg1.SelectedPath);
            }
        }

        private void btnPlugsBrowse_Click(object sender, RoutedEventArgs e)
        {
            ChoFolderBrowserDialog dlg1 = new ChoFolderBrowserDialog
            {
                Description = "Choose plug-ins folder...",
                ShowNewFolderButton = true,
                ShowEditBox = true,
                ShowBothFilesAndFolders = false,
                NewStyle = true,
                SelectedPath = (System.IO.Directory.Exists(txtPlugInsFolder.Text)) ? txtPlugInsFolder.Text : "",
                ShowFullPathInEditBox = false,
            };
            dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer;

            var result = dlg1.ShowDialog();

            if (result == System.Windows.Forms.DialogResult.OK)
            {
                if (Directory.Exists(dlg1.SelectedPath))
                    txtPlugInsFolder.Text = dlg1.SelectedPath;
                else
                    txtPlugInsFolder.Text = System.IO.Path.GetDirectoryName(dlg1.SelectedPath);
            }
        }

        private void btnMoveCopyBrowse_Click(object sender, RoutedEventArgs e)
        {
            ChoFolderBrowserDialog dlg1 = new ChoFolderBrowserDialog
            {
                Description = "Choose copy/move folder to...",
                ShowNewFolderButton = true,
                ShowEditBox = true,
                ShowBothFilesAndFolders = false,
                NewStyle = true,
                SelectedPath = (System.IO.Directory.Exists(txtCopyMoveToFolder.Text)) ? txtCopyMoveToFolder.Text : "",
                ShowFullPathInEditBox = false,
            };
            dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer;

            var result = dlg1.ShowDialog();

            if (result == System.Windows.Forms.DialogResult.OK)
            {
                if (Directory.Exists(dlg1.SelectedPath))
                    txtCopyMoveToFolder.Text = dlg1.SelectedPath;
                else
                    txtCopyMoveToFolder.Text = System.IO.Path.GetDirectoryName(dlg1.SelectedPath);
            }
        }

        private void Window_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] droppedFilePaths =
                e.Data.GetData(DataFormats.FileDrop, true) as string[];

                foreach (string droppedFilePath in droppedFilePaths)
                {
                    AddToFilesListBox(droppedFilePath);
                }
            }
        }

        private void AddToFilesListBox(string folders)
        {
            if (folders.IsNullOrWhiteSpace())
                return;

            foreach (string folder in folders.SplitNTrim())
            {
                if (folder.IsNullOrWhiteSpace()) continue;

                string folderPath = System.IO.Path.GetFullPath(folder.Trim());

                if (Directory.Exists(folderPath) && !FindByValue(lstFolders, folderPath))
                {
                    lstFolders.Items.Add(folderPath);
                }
            }
        }

        private bool FindByValue(ListBox ddl, string value)
        {
            bool isFound = false;
            foreach (string item in ddl.Items)
            {
                if (string.Compare(value, item, true) == 0)
                {
                    isFound = true;
                    break;
                }
            }

            return isFound;
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            ChoFramework.Shutdown(); 
        }

        private void ProcessFiles()
        {
            try
            {
                _isRunning = true;

                _fileProcessor = new ChoFileFolderProcessor();
                _fileProcessor.Status += (sender, e) => SetStatusMsg(e.Message);
                _fileProcessor.AppStatus += (sender, e) => UpdateStatus(e.Message, e.CleanupStatus == ChoFileProcessStatus.SUCCESS);
                foreach (string folder  in lstFolders.Items)
                {
                    if (_cancelOps)
                        break;

                    //string folder = lstFolders.Items[0].ToString();

                    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                        new Action<string>((text) =>
                            {
                                //lstFolders.Items.Remove(text);
                                lstFolders.SelectedItem = text;
                                UpdateStatus("Ready", false);
                            }),
                         folder);

                    _fileProcessor.Process(folder);
                }
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception ex)
            {
                SetStatusMsg(ex.ToString());
            }
            finally
            {
                _isRunning = false;
                _fileProcessor = null;
                _undoFilePath = ChoUndoFileProcessManager.Default.Value.Save();
            }
        }

        private void SetStatusMsg(string msg)
        {
            if (msg.IsNullOrWhiteSpace()) return;

            if (Thread.CurrentThread != _mainUIThread)
            {
                this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() => SetStatusMsg(msg)));
            }
            else
            {
                ChoTrace.Debug(msg);
                txtStatus.Text += msg + Environment.NewLine;

                //while (txtStatus.LineCount > _appSettings.MaxStatusMsgSize)
                //{
                //    int numOfLines = 30;
                //    var lines = txtStatus.Text.Lin;
                //    var newLines = lines.Skip(_appSettings.MaxStatusMsgSize);

                //    this.textBox1.Lines = newLines.ToArray();
                    
                //    txtStatus.Lin(txtStatus.Items.Count - 1);
                //}
                
                txtStatus.ScrollToEnd();
            }
        }

        private void UpdateStatus(string text, bool setTooltipStatus)
        {
            sbAppStatus.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
                {
                    sbAppStatus.Text = text;
                    if (setTooltipStatus)
                        ShowBalloonTipText(text);
                }));
        }

        private void ShowBalloonTipText(string msg)
        {
            if (ChoApplication.NotifyIcon != null)
            {
                ChoApplication.NotifyIcon.BalloonTipText = msg;
                ChoApplication.NotifyIcon.ShowBalloonTip(500);
            }
        }

        private void btnPlugIns_Click(object sender, RoutedEventArgs e)
        {
            if (!VerifyPlugInsDef())
                return;

            ChoPlugInEditorSettings plugInEditorSettings = new ChoPlugInEditorSettings();
            plugInEditorSettings.AfterConfigurationObjectLoaded += plugInEditorSettings_AfterConfigurationObjectLoaded;

            System.Windows.Forms.Application.EnableVisualStyles();
            ChoPlugInEditor p1 = new ChoPlugInEditor(_appSettings.GetPlugInsDefFile(), ChoAppSettings.MATCH_FILE_OPS_TAG, false); //@"C:\Personal\Cinchoo Source\2013-11-05\Cinchoo\Cinchoo.Core\bin\Release\t.plg");
            p1.BeforeAddNewPlugIn += BeforeAddNewPlugIn;
            //p1.Arguments = "{0} {1}".FormatString(_appSettings.PreviewMode);
            p1.ShowInTaskbar = false;
            p1.ShowDialog();

            SavePlugInDef(p1.ToXml());
        }

        private void SavePlugInDef(string xml)
        {
            _appSettings.PlugInsDef = xml;
        }

        private bool VerifyPlugInsDef()
        {
            try
            {
                _appSettings.VerifyPlugInsDef();
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error verifying PlugIn definition file.\n{0}".FormatString(ex.Message), Caption, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
        }

        private void plugInEditorSettings_AfterConfigurationObjectLoaded(object sender, ChoConfigurationObjectEventArgs e)
        {
            ChoPlugInEditorSettings plugInEditorSettings = sender as ChoPlugInEditorSettings;
            if (plugInEditorSettings == null) return;

            plugInEditorSettings.NewPlugInDefFileVisible = false;
            plugInEditorSettings.OpenPlugInDefFileVisible = false;
            plugInEditorSettings.SaveAsPlugInDefFileVisible = false;
            plugInEditorSettings.SavePlugInDefFileVisible = false;

            plugInEditorSettings.AddNewPlugInsGroupEnabled = false;
            plugInEditorSettings.RenamePlugInsGroupEnabled = false;
            plugInEditorSettings.DeletePlugInsGroupEnabled = false;
        }

        private void OnPlugInDefFileReset(object sender, RoutedEventArgs e)
        {
            MessageBoxResult r = MessageBox.Show("Are you sure you want to reset the definitions?", Caption, MessageBoxButton.YesNo, MessageBoxImage.Question);
            if (r == MessageBoxResult.No)
                return;

            _appSettings.ResetPlugInsDef();
        }

        //private void OnPlugInDefFileOpen(object sender, RoutedEventArgs e)
        //{
        //    OpenFileDialog dlg = new OpenFileDialog();
        //    dlg.Filter = "PlugIn files|*{0}".FormatString(AppHost.PlugInFileExt);

        //    var result = dlg.ShowDialog();

        //    if (result == true)
        //        _appSettings.PlugInsDefFilePath = dlg.FileName;
        //}

        private void tbrMain_Loaded(object sender, RoutedEventArgs e)
        {
            ToolBar toolBar = sender as ToolBar;
            var overflowGrid = toolBar.Template.FindName("OverflowGrid", toolBar) as FrameworkElement;
            if (overflowGrid != null)
            {
                overflowGrid.Visibility = Visibility.Collapsed;
            }
            var mainPanelBorder = toolBar.Template.FindName("MainPanelBorder", toolBar) as FrameworkElement;
            if (mainPanelBorder != null)
            {
                mainPanelBorder.Margin = new Thickness();
            }
        }

        private void btnRun_Click(object sender, RoutedEventArgs e)
        {
            _cancelOps = false;
            _undoFilePath = null;
            _fileNameProcessThread = new Thread(new ThreadStart(ProcessFiles));
            _fileNameProcessThread.IsBackground = true;
            _fileNameProcessThread.Start();
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            if (MessageBox.Show(@"Are you sure you want to stop the operation?", Caption, MessageBoxButton.YesNo, MessageBoxImage.Stop, MessageBoxResult.No)
                == MessageBoxResult.No)
                return;

            using (new ChoWPFWaitCursor())
            {
                _cancelOps = true;
                Thread.Sleep(1000);

                if (_isUndoRunning)
                {
                    //ChoFileFolderProcessor undoFileNamer = _undoFileProcessor;
                    //if (undoFileNamer != null)
                    //    undoFileNamer.CancelUndo();
                    Thread undoProcessorThread = _undoProcessThread;
                    if (undoProcessorThread != null)
                    {
                        try
                        {
                            undoProcessorThread.Abort();
                        }
                        catch (ThreadAbortException)
                        {
                            Thread.ResetAbort();
                        }
                        _undoProcessThread = null;
                    }
                    return;
                }

                //ChoFileFolderProcessor fileProcessor = _fileProcessor;
                //if (fileProcessor != null)
                //    fileProcessor.CancelProcessing();

                Thread fileNameProcessorThread = _fileNameProcessThread;
                if (fileNameProcessorThread != null)
                {
                    try
                    {
                        fileNameProcessorThread.Abort();
                    }
                    catch (ThreadAbortException)
                    {
                        Thread.ResetAbort();
                    }
                    _fileNameProcessThread = null;
                }
                //_undoFilePath = ChoUndoFileProcessManager.Default.Value.Save();
            }
        }

        private void btnDeleteFolder_Click(object sender, RoutedEventArgs e)
        {
            string[] selectedItems = new string[lstFolders.SelectedItems.Count];
            lstFolders.SelectedItems.CopyTo(selectedItems, 0);

            IsDirty = true;
            foreach (string filePath in selectedItems)
                lstFolders.Items.Remove(filePath);
        }

        private void btnAddFolder_Click(object sender, RoutedEventArgs e)
        {
            if (txtFolder.Text.IsNullOrWhiteSpace())
                return;

            IsDirty = true;

            AddToFilesListBox(txtFolder.Text);
            txtFolder.Text = "";
        }

        private void btnSaveAsFile_Click(object sender, RoutedEventArgs e)
        {
            SaveSettings(true);
        }

        private void btnSaveFile_Click(object sender, RoutedEventArgs e)
        {
            SaveSettings(false);
        }

        private bool SaveSettings()
        {
            if (IsDirty)
            {
                string msg;
                if (SettingsFilePath.IsNullOrWhiteSpace())
                    msg = "Do you want to save settings changes to untitled?";
                else
                    msg = "Do you want to save settings changes to '{0}'?".FormatString(Path.GetFileName(SettingsFilePath));
                MessageBoxResult r = MessageBox.Show(msg, Caption, MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
                if (r == MessageBoxResult.Cancel)
                    return true;
                else if (r == MessageBoxResult.No)
                {
                    IsDirty = false;
                    return false;
                }
                else
                    return !SaveSettings(false);
            }
            return false;
        }

        private bool SaveSettings(bool newFile)
        {
            SaveDirectories();

            if (newFile || SettingsFilePath.IsNullOrWhiteSpace())
            {
                SaveFileDialog dlg = new SaveFileDialog();
                dlg.DefaultExt = AppHost.AppFileExt;
                dlg.Filter = "Settings files|*{0}".FormatString(AppHost.AppFileExt);

                var result = dlg.ShowDialog();

                if (result == true)
                    SettingsFilePath = dlg.FileName;
                else
                    return false;
            }

            try
            {
                if (SettingsFilePath.IsNullOrWhiteSpace()) return true;
                File.WriteAllText(SettingsFilePath, _appSettings.ToXml());
                IsDirty = false;
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed saving settings to file. {0}".FormatString(ex.Message), this.Caption, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
        }

        private void btnOpenFile_Click(object sender, RoutedEventArgs e)
        {
            if (SaveSettings())
                return;

            OpenFileDialog dlg = new OpenFileDialog();
            dlg.DefaultExt = AppHost.AppFileExt;
            dlg.Filter = "Settings files|*{0}".FormatString(AppHost.AppFileExt);

            var result = dlg.ShowDialog();

            if (result == true)
            {
                SettingsFilePath = dlg.FileName;
                _appSettings.LoadXml(File.ReadAllText(SettingsFilePath));
                lstFolders.Items.Clear();
                if (!_appSettings.Directories.IsNullOrWhiteSpace())
                    AddToFilesListBox(_appSettings.Directories);
                IsDirty = false;
            }
        }

        private void btnNewFile_Click(object sender, RoutedEventArgs e)
        {
            if (SaveSettings())
                return;

            SettingsFilePath = null;
            lstFolders.Items.Clear();
            _appSettings.Reset();
            this.DataContext = null;
            this.DataContext = _bindObj;
            IsDirty = false;
        }

        private void btnClear_Click(object sender, RoutedEventArgs e)
        {
            txtStatus.Text = String.Empty;
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            //_wndClosing = true;
            if (_isRunning)
            {
                if (MessageBox.Show("File operation is in progress. Are you sure want to close the application?", Caption, MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
                    return;
            }

            e.Cancel = SaveSettings();
        }

        private void btnUndo_Click(object sender, RoutedEventArgs e)
        {
            if (_undoFilePath.IsNullOrWhiteSpace() || !File.Exists(_undoFilePath))
                return;

            if (MessageBox.Show("Are you sure want to undo the file operations?", Caption, MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.No)
                return;

            _undoProcessThread = new Thread(() =>
                {
                    _isUndoRunning = _isRunning = true;
                    SetStatusMsg("Undoing the file processing [Undo FilePath: {0}]...".FormatString(_undoFilePath));
                    try
                    {
                        _undoFileProcessor = new ChoFileFolderProcessor();
                        string output = _undoFileProcessor.Undo(_undoFilePath);
                        if (!output.IsNullOrWhiteSpace())
                            SetStatusMsg(output);

                        SetStatusMsg("Undoing the file processing successfully completed.");
                        _undoFilePath = null;
                    }
                    catch (Exception ex)
                    {
                        SetStatusMsg("Undoing the file processing failed. \n{0}.".FormatString(ex.Message));
                    }
                    finally
                    {
                        _undoFileProcessor = null;
                        _isUndoRunning = _isRunning = false;
                    }
                });
            _undoProcessThread.IsBackground = true;
            _undoProcessThread.Start();
        }

        private void btnOpenExprEditor_Click(object sender, RoutedEventArgs e)
        {
            ChoExprEvaluatorFrm frm = new ChoExprEvaluatorFrm();
            frm.Evaluate += ((o1, e1) =>
                {
                    if (e1.SingleExpr)
                    {
                        string t = e1.ExprText;
                        if (t.StartsWithEx("%%") || t.StartsWithEx("{{"))
                            e1.ContextText = t.ExpandProperties(e1.ContextText);
                        else
                            e1.ContextText = "~((string)@this).{0}~".FormatString(t).ExpandProperties(e1.ContextText);
                        e1.Handled = true;
                    }
                    else
                    {
                        foreach (string t in e1.ExprText.SplitNTrim(';'))
                        {
                            if (t.StartsWithEx("%%") || t.StartsWithEx("{{"))
                                e1.ContextText = t.ExpandProperties(e1.ContextText);
                            else
                                e1.ContextText = "~~((string)@this).{0}~~".FormatString(t).ExpandProperties(e1.ContextText);
                        }
                        e1.Handled = true;
                    }
                });

            frm.ExpressionText = txtTransText.Text;
            frm.ShowDialog();
        }

        private void txtPlugInsFolder_TextChanged(object sender, TextChangedEventArgs e)
        {
        }

        private void txtPlugInsFolder_LostFocus(object sender, RoutedEventArgs e)
        {
            if (!_wndLoaded) return;

            if (txtPlugInsFolder.Text.IsNullOrWhiteSpace())
                return;

            if (_plugInsFolder == txtPlugInsFolder.Text)
                return;

            MessageBoxResult r = MessageBox.Show(@"PlugIns Folder changed, this will require restart of the application. Do you want to continue?", Caption, MessageBoxButton.YesNo, MessageBoxImage.Stop, MessageBoxResult.No);
            if (r == MessageBoxResult.No)
                return;
            else
                ChoApplication.Restart();
        }

        private void MyWindow_ContentRendered(object sender, EventArgs e)
        {
            _wndLoaded = true;
        }

        private void BeforeAddNewPlugIn(object sender, ChoPlugInEventArgs e)
        {
            if (e.PlugInGroupName.IsNullOrWhiteSpace()) return;

            ChoPlugInBuilder builder = e.PlugInBuilder;
            if (builder == null) return;

            IChoScriptExtensionObject ext = builder.PlugInBuilderProperty as IChoScriptExtensionObject;
            if (ext == null || ext.IsScriptReadonly) return;

            IChoDefaultScriptSettings o = null;
            if (e.PlugInGroupName == ChoAppSettings.BEGIN_FILE_OPS_TAG
                || e.PlugInGroupName == ChoAppSettings.SUCCESS_FILE_OPS_TAG
                || e.PlugInGroupName == ChoAppSettings.FAILED_FILE_OPS_TAG
                )
                o = new ChoBulkFileOpsDefaultScriptsSettings();
            else if (e.PlugInGroupName == ChoAppSettings.MATCH_FILE_OPS_TAG)
                o = new ChoMatchFileOpsDefaultScriptsSettings();
            else if (e.PlugInGroupName == ChoAppSettings.PROCESS_FILE_OPS_TAG)
                o = new ChoProcessFileOpsDefaultScriptsSettings();
            else if (e.PlugInGroupName == ChoAppSettings.UNDO_FILE_OPS_TAG)
                o = new ChoUndoFileOpsDefaultScriptsSettings();

            if (o == null) return;

            if (builder.PlugInBuilderProperty.ScriptType == ChoScriptType.CSharp)
            {
                ext.ScriptText = o.CSharpScript;
            }
            else if (builder.PlugInBuilderProperty.ScriptType == ChoScriptType.VBNet)
            {
                ext.ScriptText = o.VBNetScript;
            }
            else if (builder.PlugInBuilderProperty.ScriptType == ChoScriptType.DOSScript)
            {
                ext.ScriptText = o.DOSScript;
            }
            else if (builder.PlugInBuilderProperty.ScriptType == ChoScriptType.JavaScript)
            {
                ext.ScriptText = o.JavaScript;
            }
            else if (builder.PlugInBuilderProperty.ScriptType == ChoScriptType.VBScript)
            {
                ext.ScriptText = o.VBScript;
            }
        }

        private void txtFolder_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                btnAddFolder_Click(sender, e);
            }
        }

        private void btnRegexHelp_Click(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Process.Start("https://msdn.microsoft.com/en-us/library/az24scfc%28v=vs.110%29.aspx");
        }

        private void lstFolders_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Delete)
                btnDeleteFolder_Click(sender, null);
        }
    }

    public class BoolInverterConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter,
            System.Globalization.CultureInfo culture)
        {
            if (value is bool)
            {
                return !(bool)value;
            }
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter,
            System.Globalization.CultureInfo culture)
        {
            if (value is bool)
            {
                return !(bool)value;
            }
            return value;
        }

        #endregion
    }
}

